package com.bestcem.xm.txtanls.grpc.service;


import com.bestcem.xm.common.core.constant.RegTypes;
import com.bestcem.xm.common.core.domain.web.RpcStatusResult;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.uitls.GRpcUtil;
import com.bestcem.xm.qdes.grpc.v1.services.OpenOption;
import com.bestcem.xm.qdes.grpc.v1.services.OpenQuestion;
import com.bestcem.xm.txtanls.grpc.convert.ModelConvert;
import com.bestcem.xm.txtanls.grpc.service.param.survey.GetSurveyAnalysisProjectParam;
import com.bestcem.xm.txtanls.grpc.service.param.survey.SurveyFieldParam;
import com.bestcem.xm.txtanls.grpc.service.param.survey.UpdateOpenOptionParam;
import com.bestcem.xm.txtanls.grpc.v1.services.*;
import com.bestcem.xm.txtanls.service.SurveyService;
import com.bestcem.xm.txtanls.service.dto.analysis.AnalysisProjectDTO;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import static com.bestcem.xm.common.core.constant.Constants.DEFAULT_ARRAY_SIZE;

/**
 * 问卷分析项目相关gRpc接口
 *
 * @author XiaoYunSong <ys.xiao@idiaoyan.com>
 * @version v1.0
 * @date 2021-05-08
 */
@Slf4j
@GrpcService
public class SurveyGrpcService extends SurveyServiceGrpc.SurveyServiceImplBase {

    @Resource
    private SurveyService surveyService;

    /**
     * 查询当前问卷下所有可参与分析的开放选项
     *
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/5/13 15:59
     */
    @Override
    public void listOpenOption(ListOpenOptionRequest request, StreamObserver<ListOpenOptionResponse> responseObserver) {
        ListOpenOptionResponse.Builder builder = ListOpenOptionResponse.newBuilder();

        // 参数校验
        String surveyId = request.getSurveyId();
        if (ObjectUtils.isEmpty(surveyId) || !Pattern.matches(RegTypes.OBJECT_ID, surveyId)) {
            builder.setStatus(RpcStatusResult.error("问卷id错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        ServiceResult<List<OpenQuestion>> result = surveyService.getSurveyOpenOptions(surveyId);
        if (result.isSuccess()) {
            List<OpenOptionInfo> openOptionInfoList = new ArrayList<>();
            for (OpenQuestion questionDTO : result.getData()) {
                openOptionInfoList.add(openOptionDTOToInfo(questionDTO));
            }
            builder.addAllOpenOptions(openOptionInfoList);
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 获取问卷项目信息
     *
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/5/13 15:59
     */
    @Override
    public void getSurveyAnalysisProject(GetSurveyAnalysisProjectRequest request, StreamObserver<GetSurveyAnalysisProjectResponse> responseObserver) {
        GetSurveyAnalysisProjectResponse.Builder builder = GetSurveyAnalysisProjectResponse.newBuilder();

        // 参数校验
        GetSurveyAnalysisProjectParam param = requestToGetSurveyAnalysisProjectParam(request);
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        ServiceResult<AnalysisProjectDTO> result = surveyService.getSurveyAnalysisProject(param);
        if (result.isSuccess()) {
            builder.setProject(ModelConvert.analysisProjectDtoToInfo(result.getData()));
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 更新问卷项目开放选项
     *
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/5/13 15:59
     */
    @Override
    public void updateOpenOption(UpdateOpenOptionRequest request, StreamObserver<UpdateOpenOptionResponse> responseObserver) {
        UpdateOpenOptionResponse.Builder builder = UpdateOpenOptionResponse.newBuilder();

        // 参数校验
        UpdateOpenOptionParam param = requestToUpdateOpenOptionParam(request);
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        ServiceResult<AnalysisProjectDTO> serviceResult = surveyService.updateOpenOptions(param);
        if (serviceResult.isSuccess()) {
            builder.setProject(ModelConvert.analysisProjectDtoToInfo(serviceResult.getData()));
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }


    // ========================== private model convert ==========================

    private GetSurveyAnalysisProjectParam requestToGetSurveyAnalysisProjectParam(GetSurveyAnalysisProjectRequest request) {
        GetSurveyAnalysisProjectParam param = new GetSurveyAnalysisProjectParam();
        param.setSurveyId(request.getSurveyId());
        param.setUserId(request.getUserId());
        param.setOrgId(request.getOrgId());
        return param;
    }

    private UpdateOpenOptionParam requestToUpdateOpenOptionParam(UpdateOpenOptionRequest request) {
        UpdateOpenOptionParam param = new UpdateOpenOptionParam();
        param.setProjectId(request.getProjectId());
        List<SurveyFieldParam> textFieldParams = new ArrayList<>();
        List<InlineOptionInfo> textFields = request.getInlineOptionsList();
        for (InlineOptionInfo textField : textFields) {
            textFieldParams.add(new SurveyFieldParam(textField.getId(), textField.getTitle()));
        }
        param.setTextFields(textFieldParams);
        return param;
    }

    private OpenOptionInfo openOptionDTOToInfo(OpenQuestion dto) {
        OpenOptionInfo.Builder builder = OpenOptionInfo.newBuilder();
        builder.setTitle(dto.getTitle());
        builder.addAllInlineOptions(this.toOptionInfos(dto.getOptionsList()));
        return builder.build();
    }

    private List<InlineOptionInfo> toOptionInfos(List<OpenOption> openOptions) {
        List<InlineOptionInfo> inlineOptionInfos = new ArrayList<>(DEFAULT_ARRAY_SIZE);
        for (OpenOption openOption : openOptions) {
            inlineOptionInfos.add(InlineOptionInfo.newBuilder().setId(openOption.getId()).setTitle(openOption.getTitle()).build());
        }
        return inlineOptionInfos;
    }
}
